๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์๋ฐ์คํฌ๋ฆฝํธ ์๋น์ค ์์ปค๋ก ์ด์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ข ํฉ ๊ฐ์ด๋. ์ฅ์ , ๊ณผ์ , ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ค๋ฃน๋๋ค.
๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ: ์๋ฐ์คํฌ๋ฆฝํธ ์๋น์ค ์์ปค๋ก์ ์ ํ ์์ฉํ๊ธฐ
๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋์์์ด ์งํํ๊ณ ์์ต๋๋ค. ์ต๊ทผ ๊ฐ์ฅ ์ค์ํ ๋ณํ ์ค ํ๋๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๊ฐ ๊ธฐ์กด์ ์๊ตฌ์ ์ธ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง์์ ์๋ฐ์คํฌ๋ฆฝํธ ์๋น์ค ์์ปค๋ก ์ ํ๋ ๊ฒ์ ๋๋ค. ํฌ๋กฌ ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ ์ ๋งค๋ํ์คํธ V3(MV3)๊ฐ ์ฃผ๋ํ๋ ์ด ๋ง์ด๊ทธ๋ ์ด์ ์ ์๋ง์ ์ด์ ์ ๊ฐ์ ธ๋ค์ฃผ์ง๋ง, ๊ฐ๋ฐ์๋ค์๊ฒ๋ ๋ ํนํ ๊ณผ์ ๋ฅผ ์ ์ํ๊ธฐ๋ ํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋์์๋ ์ด๋ฌํ ๋ณํ์ ์ด์ , ์ฅ๋จ์ , ๊ทธ๋ฆฌ๊ณ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ํํ ์ ํ์ ๋ณด์ฅํ๊ธฐ ์ํ ์์ธํ ๋ง์ด๊ทธ๋ ์ด์ ๊ณผ์ ์ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์๋น์ค ์์ปค๋ก ๋ง์ด๊ทธ๋ ์ด์ ํด์ผ ํ๋ ์ด์
์ด ์ ํ์ ์ฃผ๋ ๋๊ธฐ๋ ๋ธ๋ผ์ฐ์ ์ฑ๋ฅ๊ณผ ๋ณด์์ ๊ฐ์ ํ๋ ๊ฒ์ ๋๋ค. ๋งค๋ํ์คํธ V2(MV2)์์ ํํ ์ฌ์ฉ๋๋ ์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง๋ ์ ํด ์ํ์ผ ๋๋ ์๋นํ ๋ฆฌ์์ค๋ฅผ ์๋นํ์ฌ ๋ฐฐํฐ๋ฆฌ ์๋ช ๊ณผ ์ ๋ฐ์ ์ธ ๋ธ๋ผ์ฐ์ ์๋ต์ฑ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. ๋ฐ๋ฉด์ ์๋น์ค ์์ปค๋ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ์๋ํ๋ฉฐ ํ์ํ ๋๋ง ํ์ฑํ๋ฉ๋๋ค.
์๋น์ค ์์ปค์ ์ฅ์ :
- ์ฑ๋ฅ ํฅ์: ์๋น์ค ์์ปค๋ API ํธ์ถ์ด๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ๋ถ๋ถ์์ ์จ ๋ฉ์์ง์ ๊ฐ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง ํ์ฑํ๋ฉ๋๋ค. ์ด๋ฌํ "์ด๋ฒคํธ ๊ธฐ๋ฐ" ํน์ฑ์ ๋ฆฌ์์ค ์๋น๋ฅผ ์ค์ด๊ณ ๋ธ๋ผ์ฐ์ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
- ๋ณด์ ๊ฐํ: ์๋น์ค ์์ปค๋ ๋ ์ ํ๋ ํ๊ฒฝ์์ ์๋ํ๋ฏ๋ก ๊ณต๊ฒฉ ํ๋ฉด์ ์ค์ด๊ณ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ ๋ฐ์ ์ธ ๋ณด์์ ํฅ์์ํต๋๋ค.
- ๋ฏธ๋ ๋๋น: ๋๋ถ๋ถ์ ์ฃผ์ ๋ธ๋ผ์ฐ์ ๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ฒ๋ฆฌ๋ฅผ ์ํ ํ์ค์ผ๋ก ์๋น์ค ์์ปค๋ฅผ ์ฑํํ๊ณ ์์ต๋๋ค. ์ง๊ธ ๋ง์ด๊ทธ๋ ์ด์ ํ๋ฉด ํ์ฅ ํ๋ก๊ทธ๋จ์ด ํธํ์ฑ์ ์ ์งํ๊ณ ํฅํ ์ง์ ์ค๋จ ๋ฌธ์ ๋ฅผ ํผํ ์ ์์ต๋๋ค.
- ๋ ผ๋ธ๋กํน(Non-Blocking) ์์ : ์๋น์ค ์์ปค๋ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์์ ์ ์ํํ๋๋ก ์ค๊ณ๋์ด ๋ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํฉ๋๋ค.
๋จ์ ๋ฐ ๊ณผ์ :
- ํ์ต ๊ณก์ : ์๋น์ค ์์ปค๋ ์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง์ ์ต์ํ ๊ฐ๋ฐ์๋ค์๊ฒ๋ ์ด๋ ค์ธ ์ ์๋ ์๋ก์ด ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ์ ๋์ ํฉ๋๋ค. ์ด๋ฒคํธ ๊ธฐ๋ฐ ํน์ฑ์ ์ํ ๋ฐ ํต์ ๊ด๋ฆฌ์ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์๊ตฌํฉ๋๋ค.
- ์๊ตฌ ์ํ ๊ด๋ฆฌ: ์๋น์ค ์์ปค๊ฐ ํ์ฑํ๋๋ ๋์ ์๊ตฌ์ ์ธ ์ํ๋ฅผ ์ ์งํ๋ ค๋ฉด ์ ์คํ ๊ณ ๋ ค๊ฐ ํ์ํฉ๋๋ค. Storage API๋ IndexedDB์ ๊ฐ์ ๊ธฐ์ ์ด ์ค์ํด์ง๋๋ค.
- ๋๋ฒ๊น ๋ณต์ก์ฑ: ์๋น์ค ์์ปค๋ ๊ฐํ์ ์ผ๋ก ์๋ํ๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง๋ณด๋ค ๋๋ฒ๊น ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
- DOM ์ ๊ทผ ์ ํ: ์๋น์ค ์์ปค๋ DOM์ ์ง์ ์ ๊ทผํ ์ ์์ต๋๋ค. ์น ํ์ด์ง์ ์ํธ ์์ฉํ๋ ค๋ฉด ์ฝํ ์ธ ์คํฌ๋ฆฝํธ์ ํต์ ํด์ผ ํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ ์ดํดํ๊ธฐ
๋ง์ด๊ทธ๋ ์ด์ ๊ณผ์ ์ ๋ฐ์ด๋ค๊ธฐ ์ ์ ์๋น์ค ์์ปค์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ํ์ ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ
์๋น์ค ์์ปค๋ ๋ค์๊ณผ ๊ฐ์ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋ ๋๋ ทํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋๋ค:
- ์ค์น(Installation): ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์ฒ์ ๋ก๋๋๊ฑฐ๋ ์ ๋ฐ์ดํธ๋ ๋ ์๋น์ค ์์ปค๊ฐ ์ค์น๋ฉ๋๋ค. ์ด๋ ์ ์ ์์ฐ์ ์บ์ํ๊ณ ์ด๊ธฐ ์ค์ ์์ ์ ์ํํ๋ ๊ฒ์ด ์ด์์ ์ ๋๋ค.
- ํ์ฑํ(Activation): ์ค์น ํ ์๋น์ค ์์ปค๊ฐ ํ์ฑํ๋ฉ๋๋ค. ์ด ์์ ๋ถํฐ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์ ํด(Idle): ์๋น์ค ์์ปค๋ ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ์ ํด ์ํ๋ฅผ ์ ์งํฉ๋๋ค.
- ์ข ๋ฃ(Termination): ์๋น์ค ์์ปค๊ฐ ๋ ์ด์ ํ์ํ์ง ์์ ๋ ์ข ๋ฃ๋ฉ๋๋ค.
์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ
์๋น์ค ์์ปค๋ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ์๋ํ๋ฉฐ, ํน์ ์ด๋ฒคํธ์ ๋ํ ์๋ต์ผ๋ก๋ง ์ฝ๋๋ฅผ ์คํํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ด๋ฒคํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- install: ์๋น์ค ์์ปค๊ฐ ์ค์น๋ ๋ ๋ฐ์ํฉ๋๋ค.
- activate: ์๋น์ค ์์ปค๊ฐ ํ์ฑํ๋ ๋ ๋ฐ์ํฉ๋๋ค.
- fetch: ๋ธ๋ผ์ฐ์ ๊ฐ ๋คํธ์ํฌ ์์ฒญ์ ํ ๋ ๋ฐ์ํฉ๋๋ค.
- message: ์๋น์ค ์์ปค๊ฐ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ๋ถ๋ถ์ผ๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ ์์ ํ ๋ ๋ฐ์ํฉ๋๋ค.
ํ๋ก์ธ์ค ๊ฐ ํต์
์๋น์ค ์์ปค๋ ์ฝํ
์ธ ์คํฌ๋ฆฝํธ๋ ํ์
์คํฌ๋ฆฝํธ์ ๊ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ๋ถ๋ถ๊ณผ ํต์ ํ ๋ฐฉ๋ฒ์ด ํ์ํฉ๋๋ค. ์ด๋ ์ผ๋ฐ์ ์ผ๋ก chrome.runtime.sendMessage ๋ฐ chrome.runtime.onMessage API๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฃจ์ด์ง๋๋ค.
๋จ๊ณ๋ณ ๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋
์ผ๋ฐ์ ์ธ ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง์์ ์๋น์ค ์์ปค๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ๊ณผ์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1๋จ๊ณ: ๋งค๋ํ์คํธ ํ์ผ(manifest.json) ์ ๋ฐ์ดํธ
์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ ์๋น์ค ์์ปค๋ก์ ๋ณ๊ฒฝ์ ๋ฐ์ํ๋๋ก manifest.json ํ์ผ์ ์
๋ฐ์ดํธํ๋ ๊ฒ์
๋๋ค. ๊ธฐ์กด์ "background" ํ๋๋ฅผ ์ ๊ฑฐํ๊ณ "service_worker" ์์ฑ์ ํฌํจํ๋ ์๋ก์ด "background" ํ๋๋ก ๊ต์ฒดํฉ๋๋ค.
๋งค๋ํ์คํธ V2 ์์ (์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง):
{
"manifest_version": 2,
"name": "My Extension",
"version": "1.0",
"background": {
"scripts": ["background.js"],
"persistent": true
},
"permissions": [
"storage",
"activeTab"
]
}
๋งค๋ํ์คํธ V3 ์์ (์๋น์ค ์์ปค):
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"permissions": [
"storage",
"activeTab"
]
}
์ค์ ๊ณ ๋ ค์ฌํญ:
manifest_version์ด 3์ผ๋ก ์ค์ ๋์๋์ง ํ์ธํ์ธ์."service_worker"์์ฑ์ ์๋น์ค ์์ปค ์คํฌ๋ฆฝํธ์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํฉ๋๋ค.
2๋จ๊ณ: ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ(background.js) ๋ฆฌํฉํ ๋ง
์ด๊ฒ์ด ๋ง์ด๊ทธ๋ ์ด์ ๊ณผ์ ์์ ๊ฐ์ฅ ์ค์ํ ๋จ๊ณ์ ๋๋ค. ์๋น์ค ์์ปค์ ์ด๋ฒคํธ ๊ธฐ๋ฐ ํน์ฑ์ ๋ง๊ฒ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฆฌํฉํ ๋งํด์ผ ํฉ๋๋ค.
1. ์๊ตฌ ์ํ ๋ณ์ ์ ๊ฑฐ
MV2 ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง์์๋ ์ ์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ์ด๋ฒคํธ์ ๊ฑธ์ณ ์ํ๋ฅผ ์ ์งํ ์ ์์์ต๋๋ค. ๊ทธ๋ฌ๋ ์๋น์ค ์์ปค๋ ์ ํด ์ํ์ผ ๋ ์ข ๋ฃ๋๋ฏ๋ก ์ ์ญ ๋ณ์๋ ์๊ตฌ ์ํ๋ฅผ ์ ์งํ๋ ๋ฐ ์ ๋ขฐํ ์ ์์ต๋๋ค.
์์ (MV2):
var counter = 0;
chrome.browserAction.onClicked.addListener(function(tab) {
counter++;
console.log("Counter: " + counter);
});
ํด๊ฒฐ์ฑ : Storage API ๋๋ IndexedDB ์ฌ์ฉ
Storage API(chrome.storage.local ๋๋ chrome.storage.sync)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ์๊ตฌ์ ์ผ๋ก ์ ์ฅํ๊ณ ๊ฒ์ํ ์ ์์ต๋๋ค. ๋ ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ์๋ IndexedDB๊ฐ ๋ ๋ค๋ฅธ ์ต์
์
๋๋ค.
์์ (MV3, Storage API ์ฌ์ฉ):
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.storage.local.get(['counter'], function(result) {
var counter = result.counter || 0;
counter++;
chrome.storage.local.set({counter: counter}, function() {
console.log("Counter: " + counter);
});
});
});
์์ (MV3, IndexedDB ์ฌ์ฉ):
// IndexedDB ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ๋ ํจ์
function openDatabase() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('myDatabase', 1);
request.onerror = (event) => {
reject('๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐ ์ค๋ฅ');
};
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
db.createObjectStore('myObjectStore', { keyPath: 'id' });
};
});
}
// IndexedDB์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
function getData(db, id) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['myObjectStore'], 'readonly');
const objectStore = transaction.objectStore('myObjectStore');
const request = objectStore.get(id);
request.onerror = (event) => {
reject('๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ');
};
request.onsuccess = (event) => {
resolve(request.result);
};
});
}
// IndexedDB์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ๋ ํจ์
function putData(db, data) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['myObjectStore'], 'readwrite');
const objectStore = transaction.objectStore('myObjectStore');
const request = objectStore.put(data);
request.onerror = (event) => {
reject('๋ฐ์ดํฐ ๋ฃ๊ธฐ ์ค๋ฅ');
};
request.onsuccess = (event) => {
resolve();
};
});
}
chrome.browserAction.onClicked.addListener(async (tab) => {
try {
const db = await openDatabase();
let counterData = await getData(db, 'counter');
let counter = counterData ? counterData.value : 0;
counter++;
await putData(db, { id: 'counter', value: counter });
db.close();
console.log("Counter: " + counter);
} catch (error) {
console.error("IndexedDB ์ค๋ฅ: ", error);
}
});
2. ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฉ์์ง ์ ๋ฌ๋ก ๋์ฒด
๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๊ฐ ์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ๋ถ๋ถ๊ณผ ํต์ ํ๋ ๊ฒฝ์ฐ, ๋ฉ์์ง ์ ๋ฌ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์์ (๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ์์ ์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ก ๋ฉ์์ง ๋ณด๋ด๊ธฐ):
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.message === "get_data") {
// ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๊ธฐ ์ํด ๋ฌด์ธ๊ฐ ์ํ
let data = "Example Data";
sendResponse({data: data});
}
}
);
์์ (์ฝํ ์ธ ์คํฌ๋ฆฝํธ์์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๋ก ๋ฉ์์ง ๋ณด๋ด๊ธฐ):
chrome.runtime.sendMessage({message: "get_data"}, function(response) {
console.log("์์ ๋ ๋ฐ์ดํฐ: " + response.data);
});
3. `install` ์ด๋ฒคํธ์์ ์ด๊ธฐํ ์์ ์ฒ๋ฆฌ
install ์ด๋ฒคํธ๋ ์๋น์ค ์์ปค๊ฐ ์ฒ์ ์ค์น๋๊ฑฐ๋ ์
๋ฐ์ดํธ๋ ๋ ๋ฐ์ํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฑ์ด๋ ์ ์ ์์ฐ ์บ์ฑ๊ณผ ๊ฐ์ ์ด๊ธฐํ ์์
์ ์ํํ๊ธฐ์ ์๋ฒฝํ ์์ ์
๋๋ค.
์์:
chrome.runtime.onInstalled.addListener(function() {
console.log("์๋น์ค ์์ปค๊ฐ ์ค์น๋์์ต๋๋ค.");
// ์ฌ๊ธฐ์ ์ด๊ธฐํ ์์
์ ์ํํฉ๋๋ค
chrome.storage.local.set({initialized: true});
});
4. ์คํ์คํฌ๋ฆฐ ๋ฌธ์ ๊ณ ๋ ค
๋งค๋ํ์คํธ V3๋ ์ค๋์ค ์ฌ์์ด๋ ํด๋ฆฝ๋ณด๋ ์ํธ ์์ฉ๊ณผ ๊ฐ์ด ์ด์ ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง์์ DOM ์ ๊ทผ์ด ํ์ํ๋ ์์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์คํ์คํฌ๋ฆฐ ๋ฌธ์๋ฅผ ๋์ ํ์ต๋๋ค. ์ด ๋ฌธ์๋ ๋ณ๋์ ์ปจํ ์คํธ์์ ์คํ๋์ง๋ง ์๋น์ค ์์ปค๋ฅผ ๋์ ํ์ฌ DOM๊ณผ ์ํธ ์์ฉํ ์ ์์ต๋๋ค.
ํ์ฅ ํ๋ก๊ทธ๋จ์ด DOM์ ๊ด๋ฒ์ํ๊ฒ ์กฐ์ํด์ผ ํ๊ฑฐ๋ ๋ฉ์์ง ์ ๋ฌ ๋ฐ ์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ก ์ฝ๊ฒ ๋ฌ์ฑํ ์ ์๋ ์์ ์ ์ํํด์ผ ํ๋ ๊ฒฝ์ฐ ์คํ์คํฌ๋ฆฐ ๋ฌธ์๊ฐ ์ฌ๋ฐ๋ฅธ ํด๊ฒฐ์ฑ ์ด ๋ ์ ์์ต๋๋ค.
์์ (์คํ์คํฌ๋ฆฐ ๋ฌธ์ ์์ฑ):
// ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ์์:
async function createOffscreen() {
if (await chrome.offscreen.hasDocument({
reasons: [chrome.offscreen.Reason.WORKER],
justification: '๋ฌธ์๊ฐ ํ์ํ ์ด์ '
})) {
return;
}
await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: [chrome.offscreen.Reason.WORKER],
justification: '๋ฌธ์๊ฐ ํ์ํ ์ด์ '
});
}
chrome.runtime.onStartup.addListener(createOffscreen);
chrome.runtime.onInstalled.addListener(createOffscreen);
์์ (offscreen.html):
<!DOCTYPE html>
<html>
<head>
<title>Offscreen Document</title>
</head>
<body>
<script src="offscreen.js"></script>
</body>
</html>
์์ (offscreen.js, ์คํ์คํฌ๋ฆฐ ๋ฌธ์์์ ์คํ๋จ):
// ์๋น์ค ์์ปค๋ก๋ถํฐ์ ๋ฉ์์ง ์์ ๋๊ธฐ
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'doSomething') {
// ์ฌ๊ธฐ์ DOM์ผ๋ก ๋ฌด์ธ๊ฐ๋ฅผ ์ํ
document.body.textContent = '์์
์ด ์ํ๋์์ต๋๋ค!';
sendResponse({ result: 'success' });
}
});
3๋จ๊ณ: ํ์ฅ ํ๋ก๊ทธ๋จ ์ฒ ์ ํ ํ ์คํธํ๊ธฐ
๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฆฌํฉํ ๋งํ ํ์๋ ์๋ก์ด ์๋น์ค ์์ปค ํ๊ฒฝ์์ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ์ฒ ์ ํ ํ ์คํธํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์ ์์ญ์ ํนํ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด์ธ์:
- ์ํ ๊ด๋ฆฌ: ์๊ตฌ ์ํ๊ฐ Storage API ๋๋ IndexedDB๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฅ๋๊ณ ๊ฒ์๋๋์ง ํ์ธํฉ๋๋ค.
- ๋ฉ์์ง ์ ๋ฌ: ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ, ์ฝํ ์ธ ์คํฌ๋ฆฝํธ, ํ์ ์คํฌ๋ฆฝํธ ๊ฐ์ ๋ฉ์์ง๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ก๋๊ณ ์์ ๋๋์ง ํ์ธํฉ๋๋ค.
- ์ด๋ฒคํธ ์ฒ๋ฆฌ: ๋ชจ๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ์์๋๋ก ํธ๋ฆฌ๊ฑฐ๋๋์ง ํ ์คํธํฉ๋๋ค.
- ์ฑ๋ฅ: ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ์ฌ ๊ณผ๋ํ ๋ฆฌ์์ค๋ฅผ ์๋นํ์ง ์๋์ง ํ์ธํฉ๋๋ค.
4๋จ๊ณ: ์๋น์ค ์์ปค ๋๋ฒ๊น ํ๊ธฐ
์๋น์ค ์์ปค๋ ๊ฐํ์ ์ผ๋ก ์๋ํ๊ธฐ ๋๋ฌธ์ ๋๋ฒ๊น ์ด ์ด๋ ค์ธ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค๋ฅผ ๋๋ฒ๊น ํ๋ ๋ฐ ๋์์ด ๋๋ ๋ช ๊ฐ์ง ํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- Chrome DevTools: Chrome DevTools๋ฅผ ์ฌ์ฉํ์ฌ ์๋น์ค ์์ปค๋ฅผ ๊ฒ์ฌํ๊ณ , ์ฝ์ ๋ก๊ทธ๋ฅผ ๋ณด๊ณ , ์ค๋จ์ ์ ์ค์ ํฉ๋๋ค. ์๋น์ค ์์ปค๋ "Application" ํญ ์๋์์ ์ฐพ์ ์ ์์ต๋๋ค.
- ์๊ตฌ ์ฝ์ ๋ก๊ทธ:
console.log๋ฌธ์ ์์ ๋กญ๊ฒ ์ฌ์ฉํ์ฌ ์๋น์ค ์์ปค์ ์คํ ํ๋ฆ์ ์ถ์ ํฉ๋๋ค. - ์ค๋จ์ : ์๋น์ค ์์ปค ์ฝ๋์ ์ค๋จ์ ์ ์ค์ ํ์ฌ ์คํ์ ์ผ์ ์ค์งํ๊ณ ๋ณ์๋ฅผ ๊ฒ์ฌํฉ๋๋ค.
- ์๋น์ค ์์ปค ๊ฒ์ฌ๊ธฐ: Chrome DevTools์ ์๋น์ค ์์ปค ๊ฒ์ฌ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ์๋น์ค ์์ปค์ ์ํ, ์ด๋ฒคํธ ๋ฐ ๋คํธ์ํฌ ์์ฒญ์ ๋ด ๋๋ค.
์๋น์ค ์์ปค ๋ง์ด๊ทธ๋ ์ด์ ๋ชจ๋ฒ ์ฌ๋ก
๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์๋น์ค ์์ปค๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ ๋ ๋ฐ๋ผ์ผ ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ผ์ฐ ์์ํ๊ธฐ: ์๋น์ค ์์ปค๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ๊ฒ์ ๋ง์ง๋ง ์๊ฐ๊น์ง ๋ฏธ๋ฃจ์ง ๋ง์ธ์. ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ ๋ง์ด๊ทธ๋ ์ด์ ํ๋ก์ธ์ค๋ฅผ ์์ํ์ฌ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ๊ณ ํ์ฅ ํ๋ก๊ทธ๋จ์ ํ ์คํธํ ์ถฉ๋ถํ ์๊ฐ์ ํ๋ณดํ์ธ์.
- ์์ ๋ถํ ํ๊ธฐ: ๋ง์ด๊ทธ๋ ์ด์ ํ๋ก์ธ์ค๋ฅผ ๋ ์๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ์์ ์ผ๋ก ๋๋์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ํ๋ก์ธ์ค๊ฐ ๋ ๋ถ๋ด์ค๋ฝ๊ณ ์ถ์ ํ๊ธฐ ์ฌ์์ง๋๋ค.
- ์์ฃผ ํ ์คํธํ๊ธฐ: ๋ง์ด๊ทธ๋ ์ด์ ๊ณผ์ ์ ๋ฐ์ ๊ฑธ์ณ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์์ฃผ ํ ์คํธํ์ฌ ์ค๋ฅ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ์ธ์.
- ์๊ตฌ ์ํ์๋ Storage API ๋๋ IndexedDB ์ฌ์ฉํ๊ธฐ: ์๊ตฌ ์ํ์ ์ ์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ์ง ๋ง์ธ์. ๋์ Storage API๋ IndexedDB๋ฅผ ์ฌ์ฉํ์ธ์.
- ํต์ ์๋ ๋ฉ์์ง ์ ๋ฌ ์ฌ์ฉํ๊ธฐ: ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ, ์ฝํ ์ธ ์คํฌ๋ฆฝํธ, ํ์ ์คํฌ๋ฆฝํธ ๊ฐ์ ํต์ ์๋ ๋ฉ์์ง ์ ๋ฌ์ ์ฌ์ฉํ์ธ์.
- ์ฝ๋ ์ต์ ํํ๊ธฐ: ๋ฆฌ์์ค ์๋น๋ฅผ ์ต์ํํ๊ธฐ ์ํด ์ฑ๋ฅ์ ์ํด ์ฝ๋๋ฅผ ์ต์ ํํ์ธ์.
- ์คํ์คํฌ๋ฆฐ ๋ฌธ์ ๊ณ ๋ คํ๊ธฐ: DOM์ ๊ด๋ฒ์ํ๊ฒ ์กฐ์ํด์ผ ํ๋ ๊ฒฝ์ฐ ์คํ์คํฌ๋ฆฐ ๋ฌธ์ ์ฌ์ฉ์ ๊ณ ๋ คํ์ธ์.
๊ตญ์ ํ ๊ณ ๋ ค์ฌํญ
์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฐํ ๋๋ ๊ตญ์ ํ(i18n)์ ํ์งํ(l10n)๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ ์ธ๊ณ ์ฌ์ฉ์๊ฐ ์ ๊ทผํ ์ ์๋๋ก ํ๋ ๋ช ๊ฐ์ง ํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- `_locales` ํด๋ ์ฌ์ฉ: ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฒ์ญ๋ ๋ฌธ์์ด์
_localesํด๋์ ์ ์ฅํฉ๋๋ค. ์ด ํด๋์๋ ์ง์๋๋ ๊ฐ ์ธ์ด์ ๋ํ ํ์ ํด๋๊ฐ ์์ผ๋ฉฐ, ๋ฒ์ญ์ด ํฌํจ๋messages.jsonํ์ผ์ด ์์ต๋๋ค. - `__MSG_messageName__` ๊ตฌ๋ฌธ ์ฌ์ฉ: ์ฝ๋์ ๋งค๋ํ์คํธ ํ์ผ์์ ๋ฒ์ญ๋ ๋ฌธ์์ด์ ์ฐธ์กฐํ ๋
__MSG_messageName__๊ตฌ๋ฌธ์ ์ฌ์ฉํฉ๋๋ค. - ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฐ๋(RTL) ์ธ์ด ์ง์: ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ ์ด์์๊ณผ ์คํ์ผ์ด ์๋์ด ๋ฐ ํ๋ธ๋ฆฌ์ด์ ๊ฐ์ RTL ์ธ์ด์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋๋์ง ํ์ธํฉ๋๋ค.
- ๋ ์ง ๋ฐ ์๊ฐ ํ์ ๊ณ ๋ ค: ๊ฐ ๋ก์ผ์ผ์ ์ ํฉํ ๋ ์ง ๋ฐ ์๊ฐ ํ์์ ์ฌ์ฉํฉ๋๋ค.
- ๋ฌธํ์ ์ผ๋ก ๊ด๋ จ๋ ์ฝํ ์ธ ์ ๊ณต: ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ฝํ ์ธ ๋ฅผ ๋ค๋ฅธ ์ง์ญ์ ๋ฌธํ์ ์ผ๋ก ๊ด๋ จ๋๋๋ก ๋ง์ถคํํฉ๋๋ค.
์์ (_locales/en/messages.json):
{
"extensionName": {
"message": "๋ด ํ์ฅ ํ๋ก๊ทธ๋จ",
"description": "ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ด๋ฆ"
},
"buttonText": {
"message": "ํด๋ฆญํ์ธ์",
"description": "๋ฒํผ์ ํ์๋ ํ
์คํธ"
}
}
์์ (์ฝ๋์์ ๋ฒ์ญ๋ ๋ฌธ์์ด ์ฐธ์กฐํ๊ธฐ):
document.getElementById('myButton').textContent = chrome.i18n.getMessage("buttonText");
๊ฒฐ๋ก
๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์๋ฐ์คํฌ๋ฆฝํธ ์๋น์ค ์์ปค๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ๊ฒ์ ์ฑ๋ฅ, ๋ณด์์ ๊ฐ์ ํ๊ณ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฏธ๋๋ฅผ ๋๋นํ๋ ์ค์ํ ๋จ๊ณ์ ๋๋ค. ์ ํ ๊ณผ์ ์์ ๋ช ๊ฐ์ง ์ด๋ ค์์ด ์์ ์ ์์ง๋ง, ๊ทธ ๋ ธ๋ ฅ์ ๊ฐ์น๋ ์ถฉ๋ถํฉ๋๋ค. ์ด ๊ฐ์ด๋์ ์ค๋ช ๋ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅด๊ณ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ฑํํจ์ผ๋ก์จ ์ํํ๊ณ ์ฑ๊ณต์ ์ธ ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ณด์ฅํ๊ณ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ๋ ๋์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค์ ํ์ ์ต๋ํ ํ์ฉํ๊ธฐ ์ํด ์ฒ ์ ํ ํ ์คํธํ๊ณ ์๋ก์ด ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ์ ์ ์ํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.